/**
 * Project Looking Glass
 *
 * $RCSfile: JInput.java,v $
 *
 * Copyright (c) 2004-2007, Sun Microsystems, Inc., All Rights Reserved
 *
 * Redistributions in source code form must reproduce the above
 * copyright and this condition.
 *
 * The contents of this file are subject to the GNU General Public
 * License, Version 2 (the "License"); you may not use this file
 * except in compliance with the License. A copy of the License is
 * available at http://www.opensource.org/licenses/gpl-license.php.
 *
 * $Revision: 1.6 $
 * $Date: 2007/05/04 23:11:40 $
 * $State: Exp $
 */
package lionel.input;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.logging.Logger;
import javax.swing.Timer;
import javax.swing.event.EventListenerList;

import net.java.games.input.Controller;
import net.java.games.input.ControllerEnvironment;


/**
 * A high level class to manage JInput devices (gamepads, joysticks etc.)
 * The <code>initialize</code> method must be called so that the JInput devices
 * can be discovered and polled. Otherwise no events will be generated.
 *
 * Objects can register themselves to receive JInput events (currently axis
 * and button events only).
 *
 * TODO: How do we deal with focus issues while delivering events...
 *
 * TODO: Currently objects cannot register to get events
 * from just on JInput device alone. This currently done globally for all JInput
 * devices. This might change in the future.
 *
 * @author Krishna Gadepalli
 */
public class JInput {
    protected static final Logger logger = Logger.getLogger("lionel.input.JInput");

    // How often should the JInput devices be polled (in milliseconds)
    public static int POLL_INTERVAL = 50;

    private static ArrayList<JInputDevice> jInputDevices = null;
    private static Timer pollTimer = null;

    /**
     * Get all the available JInputDevices and (for the time being) only
     * keep track of devices that have a joystick and/or joystick type buttons 
     **/
    public synchronized static boolean isAvailable() {

	if (jInputDevices != null) {
	    return jInputDevices.size() > 0;
	}

	jInputDevices = new ArrayList<JInputDevice>();

	// get the controllers
	Controller[] cs = null;

	try {
	    cs = ControllerEnvironment.getDefaultEnvironment().getControllers();
	} catch (Exception e) {
            System.err.println("Error initializing JInput");
	    // e.printStackTrace();
	    cs = null;
	}

	if ((cs == null) || (cs.length == 0))
	    return false;

	for (Controller c: cs) {
	    if (JInputDevice.isNavigationalDevice(c)) {
		logger.warning("+++++++ Adding JInput device:" + c.getName());
		jInputDevices.add(new JInputDevice(c));
	    }
	}
        
        if (jInputDevices.size() <= 0)
	    return false;

        return true;
    }
    
    public synchronized static boolean doPolling(boolean doPolling) {
	if (!isAvailable()) 
	    return false;

	if (doPolling) {
	    pollTimer = new Timer(POLL_INTERVAL,
			    new ActionListener() {
				public void actionPerformed(ActionEvent e) {
				    pollAllDevices();
				}
			    });
	    startPolling();

	} else if (pollTimer != null) {
	    stopPolling();
	    pollTimer = null;
	}

        return true;
    }
    
    /**
     * Get all the avaliable JInputDevices
     **/
    public static ArrayList<JInputDevice> getDevices() {
	return jInputDevices;
    }
    
    public static int getNumDevices() {
	return (jInputDevices == null) ? 0 : jInputDevices.size();
    }
    
    public static JInputDevice getDevice(int index) {
	return (jInputDevices == null) ? null : jInputDevices.get(index);
    }

    /**
     * Setup a timer to start polling the JInput devices at a specified time
     * interval - poll only if there are registered listeners...
     */
    private static void startPolling() {
	if ((pollTimer != null) ) {
	    if (!pollTimer.isRunning())
		pollTimer.start();
	}
    }

    /**
     * Stop polling if there are no registered listeners...
     */
    private static void stopPolling() {
	if ((pollTimer != null) && (listenerList.getListenerCount() <= 0)) {
	    if (pollTimer.isRunning())
		pollTimer.stop();
	}
    }

    public static void pollAllDevices() {
    	boolean somelisteners = false;
    	if (jInputDevices != null )
    		for (JInputDevice jid: jInputDevices) {
    			somelisteners |= jid.pollAndSendEvents(listenerList);
    		}
    	if ((jInputDevices == null ) || (somelisteners==false))
    		stopPolling();
    }

    protected static EventListenerList listenerList = new EventListenerList();

    public static void addAxisEventListener(AxisEventListener l) {
	listenerList.add(AxisEventListener.class, l);
	doPolling(true);
    }

    public static void removeAxisEventListener(AxisEventListener l) {
	listenerList.remove(AxisEventListener.class, l);
	stopPolling();
    }

    public static void addButtonEventListener(ButtonEventListener l) {
	listenerList.add(ButtonEventListener.class, l);
	doPolling(true);
    }

    public static void removeButtonEventListener(ButtonEventListener l) {
	listenerList.remove(ButtonEventListener.class, l);
	stopPolling();
    }
}
